#ifndef __MASKS_MANAGER_H__
#define __MASKS_MANAGER_H__

////////////////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////////////////

#include <vector>
#include "Structures.hpp"
#include <string>
#include <sstream>

////////////////////////////////////////////////////////////////////////////////
// Namespaces
////////////////////////////////////////////////////////////////////////////////

namespace SC {

////////////////////////////////////////////////////////////////////////////////
// Forward declarations
////////////////////////////////////////////////////////////////////////////////

class SCSystem;

////////////////////////////////////////////////////////////////////////////////
// Types and Structures
////////////////////////////////////////////////////////////////////////////////

/// Mask info data structure
typedef struct MaskInfo {

	/// Default constructor
	MaskInfo() {}

	/// Creates a copy of the given instance
	MaskInfo(const MaskInfo & inst)
	:	colour(inst.colour), name(inst.name), mask(inst.mask)
	{}

	/// Affectation operator
	MaskInfo & operator = (const MaskInfo & inst) {
		if (this != &inst) {
			this->colour = inst.colour;
			this->name = inst.name;
			this->mask = inst.mask;
		}
		return *this;
	}

	/// Colour
	Colour colour;

	/// Type name
	std::string name;

	/// Extended mask
	std::string mask;

};

/// Mask events
typedef enum MaskEvent {
	AddMask, RemoveMask, EditMask, ChangeMaskColour, MergeMasks, MoveMask, LoadMasks, SaveMasks
};

////////////////////////////////////////////////////////////////////////////////
// Implementation
////////////////////////////////////////////////////////////////////////////////

/// Masks manager
class MasksManager {

	public:

		/// Clear
		virtual ~MasksManager() {}

		/// Returns the masks (read-only)
		const std::vector<MaskInfo> & GetMasks() const { return this->masks; }

		/// Look for system type mask index
		const int FindSystemMaskIdx(const SC::SCSystem &) const;

		/// Clear
		virtual void Clear() { this->masks.clear(); }

	protected:

		/// Masks
		std::vector<MaskInfo> masks;

		/// Masks size
		unsigned int masks_size;

	public:

		/// Tests if the given string matches the given mask
		static const bool Match(
			const std::string & sys,
			const std::string & mask,
			unsigned int & nb_w_card,
			char wildcard
		) {
			if (sys.size() != mask.size()) return false;
			nb_w_card = 0;
			for (unsigned int i=0; i<sys.size(); ++i) {
				if (mask[i] == wildcard) ++nb_w_card;
				else if (sys[i] != mask[i]) return false;
			}
			return true;
		}

		
		/// Minimum sequence length in order to compact it
		#define COMPACT_MIN_SIZE 6

		/// Compress a (uncompressed) mask
		static const std::string CompressMask(const std::string & mask) {
			using namespace std;
			string comp_mask;
			unsigned int i=0;
			while (i<mask.size()) {
				if (!comp_mask.empty()) comp_mask += " ";
				unsigned int oc = 1;
				while ((i+oc<mask.size()) && (mask[i] == mask[i+oc])) ++oc;
				if (oc >= COMPACT_MIN_SIZE) {
					stringstream ss;
					ss << "<" << mask[i] << "," << oc << ">";
					comp_mask += ss.str();
				}
				else
					comp_mask += string(oc,mask[i]);
				i += oc;
			}
			return comp_mask;
		}

		/// Uncompress a compressed mask
		static const std::string UncompressMask(const std::string & comp_mask) {
			using namespace std;
			string mask;
			bool read_expr = false, mult_expr = false;
			string expr, mult;
			for (unsigned int i=0; i<comp_mask.size(); ++i) {
				if (comp_mask[i] == ' ') continue;
				else if (comp_mask[i] == '<') {
					expr = "";
					read_expr = true;
				}
				else if (comp_mask[i] == '>') {
					stringstream ss; ss << mult;
					unsigned int times; ss >> times;
					string init_expr = expr;
					for (unsigned int i=1; i<times; ++i)
						expr += init_expr;
					mult_expr = false;
					mask += expr;
				}
				else if (comp_mask[i] == ',') {
					read_expr = false;
					mult = "";
					mult_expr = true;
				}
				else {
					if (read_expr) expr += comp_mask[i];
					else if (mult_expr) mult += comp_mask[i];
					else mask += comp_mask[i];
				}
			}
			return mask;
		}

		/// Space up a (uncompressed) mask
		static const std::string SpaceUpMask(const std::string & mask) {
			std::string su_mask;
			unsigned int acc = 0;
			for (unsigned int i=0; i<mask.size(); ++i) {
				if (acc == 8) {
					acc = 0;
					su_mask += " ";
				}
				su_mask += mask[i];
				++acc;
			}
			return su_mask;
		}

		/// Clean a spaced up (uncompressed) mask
		static const std::string CleanMask(const std::string & su_mask) {
			std::string mask;
			for (unsigned int i=0; i<su_mask.size(); ++i)
				if (su_mask[i] != ' ')
					mask += su_mask[i];
			return mask;
		}

};

////////////////////////////////////////////////////////////////////////////////
// Closing Namespaces
////////////////////////////////////////////////////////////////////////////////

}

////////////////////////////////////////////////////////////////////////////////

#endif
